home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume21 / amd / part08 < prev    next >
Encoding:
Internet Message Format  |  1990-04-10  |  54.5 KB

  1. Subject:  v21i096:  An Automounter for NFS systems, Part08/13
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 588935f5 bebcb818 9ce08e0c 4e7e876d
  5.  
  6. Submitted-by: Jan-Simon Pendry <jsp@doc.ic.ac.uk>
  7. Posting-number: Volume 21, Issue 96
  8. Archive-name: amd/part08
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 8 (of 13)."
  17. # Contents:  examples/amd.homes mtab.c opts.c srvr_nfs.c
  18. # Wrapped by rsalz@papaya.bbn.com on Tue Apr 10 15:12:09 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'examples/amd.homes' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'examples/amd.homes'\"
  22. else
  23. echo shar: Extracting \"'examples/amd.homes'\" \(12180 characters\)
  24. sed "s/^X//" >'examples/amd.homes' <<'END_OF_FILE'
  25. X# /homes
  26. Xzmacy26    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/zmacy26 \
  27. X    host=!toytown;type=nfs;rhost=toytown \
  28. X    host=toytown;type=ufs;dev=/dev/xy1g
  29. Xkevin    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/kpt \
  30. X    host=!toytown;type=nfs;rhost=toytown \
  31. X    host=toytown;type=ufs;dev=/dev/xy1g
  32. Xgrace    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/grace \
  33. X    host=!toytown;type=nfs;rhost=toytown \
  34. X    host=toytown;type=ufs;dev=/dev/xy1g
  35. Xaudit    type=link;fs=/etc/security/audit
  36. Xygal    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/ygal \
  37. X    host=!toytown;type=nfs;rhost=toytown \
  38. X    host=toytown;type=ufs;dev=/dev/xy1g
  39. Xacwf    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/acwf \
  40. X    host=!toytown;type=nfs;rhost=toytown \
  41. X    host=toytown;type=ufs;dev=/dev/xy1g
  42. Xrgc    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/rgc \
  43. X    host=!toytown;type=nfs;rhost=toytown \
  44. X    host=toytown;type=ufs;dev=/dev/xy1g
  45. Xlsh    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/lsh \
  46. X    host=!toytown;type=nfs;rhost=toytown \
  47. X    host=toytown;type=ufs;dev=/dev/xy1g
  48. Xjsp    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=jsp \
  49. X    host=!achilles;type=nfs;rhost=achilles \
  50. X    host=achilles;type=ufs;dev=/dev/xd0g
  51. Xjpr    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/jpr \
  52. X    host=!toytown;type=nfs;rhost=toytown \
  53. X    host=toytown;type=ufs;dev=/dev/xy1g
  54. Xjjc    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/jjc \
  55. X    host=!toytown;type=nfs;rhost=toytown \
  56. X    host=toytown;type=ufs;dev=/dev/xy1g
  57. Xids    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/ids \
  58. X    host=!toytown;type=nfs;rhost=toytown \
  59. X    host=toytown;type=ufs;dev=/dev/xy1g
  60. Xmb    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/mb \
  61. X    host=!toytown;type=nfs;rhost=toytown \
  62. X    host=toytown;type=ufs;dev=/dev/xy1g
  63. Xdaemon    type=link;fs=/
  64. Xteb    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=teb \
  65. X    host=!dylan;type=nfs;rhost=dylan \
  66. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  67. Xshc    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=shc \
  68. X    host=!dylan;type=nfs;rhost=dylan \
  69. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  70. Xmwg    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=mwg \
  71. X    host=!achilles;type=nfs;rhost=achilles \
  72. X    host=achilles;type=ufs;dev=/dev/xd0g
  73. Xmrs    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=mrs \
  74. X    host=!achilles;type=nfs;rhost=achilles \
  75. X    host=achilles;type=ufs;dev=/dev/xd0g
  76. Xjfc    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/jfc \
  77. X    host=!toytown;type=nfs;rhost=toytown \
  78. X    host=toytown;type=ufs;dev=/dev/xy1g
  79. Xdme    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=dme \
  80. X    host=!achilles;type=nfs;rhost=achilles \
  81. X    host=achilles;type=ufs;dev=/dev/xd0g
  82. Xccm    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/ccm \
  83. X    host=!toytown;type=nfs;rhost=toytown \
  84. X    host=toytown;type=ufs;dev=/dev/xy1g
  85. Xpt    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=dov/pt \
  86. X    host=!toytown;type=nfs;rhost=toytown \
  87. X    host=toytown;type=ufs;dev=/dev/xy1g
  88. Xds    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/ds \
  89. X    host=!toytown;type=nfs;rhost=toytown \
  90. X    host=toytown;type=ufs;dev=/dev/xy1g
  91. Xdg    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=dov/dg \
  92. X    host=!toytown;type=nfs;rhost=toytown \
  93. X    host=toytown;type=ufs;dev=/dev/xy1g
  94. Xwmvh    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=wmvh \
  95. X    host=!dylan;type=nfs;rhost=dylan \
  96. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  97. Xroot    type=link;fs=/
  98. Xlmjm    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/lmjm \
  99. X    host=!toytown;type=nfs;rhost=toytown \
  100. X    host=toytown;type=ufs;dev=/dev/xy1g
  101. Xsjk    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/sjk \
  102. X    host=!toytown;type=nfs;rhost=toytown \
  103. X    host=toytown;type=ufs;dev=/dev/xy1g
  104. Xmdr    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=mdr \
  105. X    host=!achilles;type=nfs;rhost=achilles \
  106. X    host=achilles;type=ufs;dev=/dev/xd0g
  107. Xkdr    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=kdr \
  108. X    host=!dylan;type=nfs;rhost=dylan \
  109. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  110. Xbrg    -opts=rw,grpid,nosuid;rfs=/home/gummo;sublink=users/brg \
  111. X    host=!gummo;type=nfs;rhost=gummo \
  112. X    host=gummo;type=ufs;dev=/dev/xy0g
  113. Xadh    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=adh \
  114. X    host=!dylan;type=nfs;rhost=dylan \
  115. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  116. Xjs    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/js \
  117. X    host=!toytown;type=nfs;rhost=toytown \
  118. X    host=toytown;type=ufs;dev=/dev/xy1g
  119. Xca    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=diadem/ca \
  120. X    host=!toytown;type=nfs;rhost=toytown \
  121. X    host=toytown;type=ufs;dev=/dev/xy1g
  122. Xbh    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/bh \
  123. X    host=!toytown;type=nfs;rhost=toytown \
  124. X    host=toytown;type=ufs;dev=/dev/xy1g
  125. Xnobody    type=link;fs=/
  126. Xingres    type=link;fs=/usr/ingres
  127. Xtsem    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/tsem \
  128. X    host=!toytown;type=nfs;rhost=toytown \
  129. X    host=toytown;type=ufs;dev=/dev/xy1g
  130. Xpm2    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=pm2 \
  131. X    host=!dylan;type=nfs;rhost=dylan \
  132. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  133. Xsm    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/sm \
  134. X    host=!toytown;type=nfs;rhost=toytown \
  135. X    host=toytown;type=ufs;dev=/dev/xy1g
  136. Xpm    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=pm \
  137. X    host=!achilles;type=nfs;rhost=achilles \
  138. X    host=achilles;type=ufs;dev=/dev/xd0g
  139. Xmd    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=md \
  140. X    host=!achilles;type=nfs;rhost=achilles \
  141. X    host=achilles;type=ufs;dev=/dev/xd0g
  142. Xjg    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/jg \
  143. X    host=!toytown;type=nfs;rhost=toytown \
  144. X    host=toytown;type=ufs;dev=/dev/xy1g
  145. Xphjk    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/phjk \
  146. X    host=!toytown;type=nfs;rhost=toytown \
  147. X    host=toytown;type=ufs;dev=/dev/xy1g
  148. Xiccp    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/iccp \
  149. X    host=!toytown;type=nfs;rhost=toytown \
  150. X    host=toytown;type=ufs;dev=/dev/xy1g
  151. Xsza    -opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=sza \
  152. X    host=!ganymede;type=nfs;rhost=ganymede \
  153. X    host=ganymede;type=ufs;dev=/dev/xy0h
  154. Xclh    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/clh \
  155. X    host=!toytown;type=nfs;rhost=toytown \
  156. X    host=toytown;type=ufs;dev=/dev/xy1g
  157. Xnd    -opts=rw,grpid,nosuid;rfs=/home/gummo;sublink=users/nd \
  158. X    host=!gummo;type=nfs;rhost=gummo \
  159. X    host=gummo;type=ufs;dev=/dev/xy0g
  160. Xmg    -opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=mg \
  161. X    host=!ganymede;type=nfs;rhost=ganymede \
  162. X    host=ganymede;type=ufs;dev=/dev/xy0h
  163. Xbp    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/bp \
  164. X    host=!toytown;type=nfs;rhost=toytown \
  165. X    host=toytown;type=ufs;dev=/dev/xy1g
  166. Xsync    type=link;fs=/
  167. Xnews    type=link;fs=/var/spool/news
  168. Xshb    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/shb \
  169. X    host=!toytown;type=nfs;rhost=toytown \
  170. X    host=toytown;type=ufs;dev=/dev/xy1g
  171. Xrjq    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=rjq \
  172. X    host=!achilles;type=nfs;rhost=achilles \
  173. X    host=achilles;type=ufs;dev=/dev/xd0g
  174. Xfst    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=fst \
  175. X    host=!dylan;type=nfs;rhost=dylan \
  176. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  177. Xeaa    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=dov/eaa \
  178. X    host=!toytown;type=nfs;rhost=toytown \
  179. X    host=toytown;type=ufs;dev=/dev/xy1g
  180. Xsw    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/sw \
  181. X    host=!toytown;type=nfs;rhost=toytown \
  182. X    host=toytown;type=ufs;dev=/dev/xy1g
  183. Xhf    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/hf \
  184. X    host=!toytown;type=nfs;rhost=toytown \
  185. X    host=toytown;type=ufs;dev=/dev/xy1g
  186. Xlkcl    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=lkcl \
  187. X    host=!dylan;type=nfs;rhost=dylan \
  188. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  189. Xchlo    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/chlo \
  190. X    host=!toytown;type=nfs;rhost=toytown \
  191. X    host=toytown;type=ufs;dev=/dev/xy1g
  192. Xesh    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/esh \
  193. X    host=!toytown;type=nfs;rhost=toytown \
  194. X    host=toytown;type=ufs;dev=/dev/xy1g
  195. Xtm    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/tm \
  196. X    host=!toytown;type=nfs;rhost=toytown \
  197. X    host=toytown;type=ufs;dev=/dev/xy1g
  198. Xok    -opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=ok \
  199. X    host=!ganymede;type=nfs;rhost=ganymede \
  200. X    host=ganymede;type=ufs;dev=/dev/xy0h
  201. Xja    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/ja \
  202. X    host=!toytown;type=nfs;rhost=toytown \
  203. X    host=toytown;type=ufs;dev=/dev/xy1g
  204. Xdp    -opts=rw,grpid,nosuid;rfs=/home/gummo;sublink=usersdiana \
  205. X    host=!gummo;type=nfs;rhost=gummo \
  206. X    host=gummo;type=ufs;dev=/dev/xy0g
  207. Xzmact03    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/zmact03 \
  208. X    host=!toytown;type=nfs;rhost=toytown \
  209. X    host=toytown;type=ufs;dev=/dev/xy1g
  210. Xuucp    type=link;fs=/var/spool/uucppublic
  211. Xsme    -opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=sme \
  212. X    host=!ganymede;type=nfs;rhost=ganymede \
  213. X    host=ganymede;type=ufs;dev=/dev/xy0h
  214. Xrjc    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/rjc \
  215. X    host=!toytown;type=nfs;rhost=toytown \
  216. X    host=toytown;type=ufs;dev=/dev/xy1g
  217. Xpdg    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/pdg \
  218. X    host=!toytown;type=nfs;rhost=toytown \
  219. X    host=toytown;type=ufs;dev=/dev/xy1g
  220. Xdgb    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=dgb \
  221. X    host=!dylan;type=nfs;rhost=dylan \
  222. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  223. Xdds    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/dds \
  224. X    host=!toytown;type=nfs;rhost=toytown \
  225. X    host=toytown;type=ufs;dev=/dev/xy1g
  226. Xih    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/ih \
  227. X    host=!toytown;type=nfs;rhost=toytown \
  228. X    host=toytown;type=ufs;dev=/dev/xy1g
  229. Xumacd20    -opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=umacd20 \
  230. X    host=!ganymede;type=nfs;rhost=ganymede \
  231. X    host=ganymede;type=ufs;dev=/dev/xy0h
  232. Xsysdiag    type=link;fs=/usr/diag/sysdiag
  233. Xgames    type=link;fs=/usr/games
  234. Xsjv    -opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=sjv \
  235. X    host=!ganymede;type=nfs;rhost=ganymede \
  236. X    host=ganymede;type=ufs;dev=/dev/xy0h
  237. Xll1    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/ll1 \
  238. X    host=!toytown;type=nfs;rhost=toytown \
  239. X    host=toytown;type=ufs;dev=/dev/xy1g
  240. Xksa    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/ksa \
  241. X    host=!toytown;type=nfs;rhost=toytown \
  242. X    host=toytown;type=ufs;dev=/dev/xy1g
  243. Xjvp    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/jvp \
  244. X    host=!toytown;type=nfs;rhost=toytown \
  245. X    host=toytown;type=ufs;dev=/dev/xy1g
  246. Xbin    type=link;fs=/bin
  247. Xsa    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/sa \
  248. X    host=!toytown;type=nfs;rhost=toytown \
  249. X    host=toytown;type=ufs;dev=/dev/xy1g
  250. Xbt    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/bt \
  251. X    host=!toytown;type=nfs;rhost=toytown \
  252. X    host=toytown;type=ufs;dev=/dev/xy1g
  253. Xwrdo    -opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=wrdo \
  254. X    host=!ganymede;type=nfs;rhost=ganymede \
  255. X    host=ganymede;type=ufs;dev=/dev/xy0h
  256. Xthp    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=thp \
  257. X    host=!achilles;type=nfs;rhost=achilles \
  258. X    host=achilles;type=ufs;dev=/dev/xd0g
  259. Xsys    type=link;fs=/
  260. Xssp    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/ssp \
  261. X    host=!toytown;type=nfs;rhost=toytown \
  262. X    host=toytown;type=ufs;dev=/dev/xy1g
  263. Xsph    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/sph \
  264. X    host=!toytown;type=nfs;rhost=toytown \
  265. X    host=toytown;type=ufs;dev=/dev/xy1g
  266. Xpah    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/pah \
  267. X    host=!toytown;type=nfs;rhost=toytown \
  268. X    host=toytown;type=ufs;dev=/dev/xy1g
  269. Xnjw    -opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=njw \
  270. X    host=!dylan;type=nfs;rhost=dylan \
  271. X    host=dylan;type=ufs;dev=/dev/dsk/2s0
  272. Xmwt    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=mwt \
  273. X    host=!achilles;type=nfs;rhost=achilles \
  274. X    host=achilles;type=ufs;dev=/dev/xd0g
  275. Xmjh    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/mjh \
  276. X    host=!toytown;type=nfs;rhost=toytown \
  277. X    host=toytown;type=ufs;dev=/dev/xy1g
  278. Xkpt    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/kpt \
  279. X    host=!toytown;type=nfs;rhost=toytown \
  280. X    host=toytown;type=ufs;dev=/dev/xy1g
  281. Xfcs    -opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=fcs \
  282. X    host=!ganymede;type=nfs;rhost=ganymede \
  283. X    host=ganymede;type=ufs;dev=/dev/xy0h
  284. Xdwj    -opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=dwj \
  285. X    host=!achilles;type=nfs;rhost=achilles \
  286. X    host=achilles;type=ufs;dev=/dev/xd0g
  287. Xhd    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/hd \
  288. X    host=!toytown;type=nfs;rhost=toytown \
  289. X    host=toytown;type=ufs;dev=/dev/xy1g
  290. Xcw    -opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/cw \
  291. X    host=!toytown;type=nfs;rhost=toytown \
  292. X    host=toytown;type=ufs;dev=/dev/xy1g
  293. END_OF_FILE
  294. if test 12180 -ne `wc -c <'examples/amd.homes'`; then
  295.     echo shar: \"'examples/amd.homes'\" unpacked with wrong size!
  296. fi
  297. # end of 'examples/amd.homes'
  298. fi
  299. if test -f 'mtab.c' -a "${1}" != "-c" ; then 
  300.   echo shar: Will not clobber existing file \"'mtab.c'\"
  301. else
  302. echo shar: Extracting \"'mtab.c'\" \(12010 characters\)
  303. sed "s/^X//" >'mtab.c' <<'END_OF_FILE'
  304. X/*
  305. X * $Id: mtab.c,v 5.1.1.3 90/01/11 17:11:26 jsp Exp Locker: jsp $
  306. X *
  307. X * Copyright (c) 1989 Jan-Simon Pendry
  308. X * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
  309. X * Copyright (c) 1989 The Regents of the University of California.
  310. X * All rights reserved.
  311. X *
  312. X * This code is derived from software contributed to Berkeley by
  313. X * Jan-Simon Pendry at Imperial College, London.
  314. X *
  315. X * Redistribution and use in source and binary forms are permitted
  316. X * provided that the above copyright notice and this paragraph are
  317. X * duplicated in all such forms and that any documentation,
  318. X * advertising materials, and other materials related to such
  319. X * distribution and use acknowledge that the software was developed
  320. X * by Imperial College of Science, Technology and Medicine, London, UK.
  321. X * The names of the College and University may not be used to endorse
  322. X * or promote products derived from this software without specific
  323. X * prior written permission.
  324. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  325. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  326. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  327. X *
  328. X *    %W% (Berkeley) %G%
  329. X */
  330. X
  331. X#include "am.h"
  332. X
  333. X/*
  334. X * Firewall /etc/mtab entries
  335. X */
  336. X#define    MTAB_STRIPNL
  337. X
  338. X/*
  339. X * Do strict /etc/mtab locking
  340. X */
  341. X#define MTAB_LOCKING
  342. X
  343. X#ifdef READ_MTAB_FROM_FILE
  344. X#ifdef USE_FCNTL
  345. X#include <fcntl.h>
  346. X#else
  347. X#include <sys/file.h>
  348. X#endif
  349. X#endif
  350. X
  351. X#ifdef READ_MTAB_ULTRIX_STYLE
  352. X#include <sys/mount.h>
  353. X#include <sys/fs_types.h>
  354. X#endif
  355. X
  356. X#ifdef READ_MTAB_BSD_STYLE
  357. X#include <sys/mount.h>
  358. X#endif
  359. X
  360. X#ifdef UPDATE_MTAB
  361. X#include <sys/stat.h>
  362. Xstatic FILE *mnt_file;
  363. X
  364. X/*
  365. X * If the system is being trashed by something, then
  366. X * opening mtab may fail with ENFILE.  So, go to sleep
  367. X * for a second and try again. (Yes - this has happened to me.)
  368. X *
  369. X * Note that this *may* block the automounter, oh well. 
  370. X * If we get to this state then things are badly wrong anyway...
  371. X *
  372. X * Give the system 10 seconds to recover but then give up.
  373. X * Hopefully something else will exit and free up some file
  374. X * table slots in that time.
  375. X */
  376. X#define    NFILE_RETRIES    10 /* seconds */
  377. X
  378. X#endif /* UPDATE_MTAB */
  379. X
  380. X#ifdef MTAB_LOCKING
  381. X#ifdef LOCK_FCNTL
  382. Xstatic int lock(fd)
  383. X{
  384. X    int rc;
  385. X    struct flock lk;
  386. X
  387. X    lk.l_type = F_WRLCK;
  388. X    lk.l_whence = 0;
  389. X    lk.l_start = 0;
  390. X    lk.l_len = 0;
  391. X
  392. Xagain:
  393. X    rc = fcntl(fd, F_SETLKW, (caddr_t) &lk);
  394. X    if (rc < 0 && (errno == EACCES || errno == EAGAIN)) {
  395. X#ifdef DEBUG
  396. X        dlog("Blocked, trying to obtain exclusive mtab lock");
  397. X#endif
  398. X        sleep(1);
  399. X        goto again;
  400. X    }
  401. X    return rc;
  402. X}
  403. X#else
  404. X#define lock(fd) (flock((fd), LOCK_EX))
  405. X#endif
  406. X#endif /* MTAB_LOCKING */
  407. X
  408. X#ifdef MTAB_STRIPNL
  409. Xstatic void mtab_stripnl(s)
  410. Xchar *s;
  411. X{
  412. X    do {
  413. X        s = strchr(s, '\n');
  414. X        if (s)
  415. X            *s++ = ' ';
  416. X    } while (s);
  417. X}
  418. X#endif
  419. X
  420. Xstatic struct mntent *mnt_dup(mp)
  421. X#ifdef READ_MTAB_BSD_STYLE
  422. Xstruct statfs *mp;
  423. X#endif
  424. X#ifdef READ_MTAB_ULTRIX_STYLE
  425. Xstruct fs_data *mp;
  426. X#endif
  427. X#ifdef READ_MTAB_FROM_FILE
  428. Xstruct mntent *mp;
  429. X#endif
  430. X{
  431. X    struct mntent *new_mp = ALLOC(mntent);
  432. X#ifdef READ_MTAB_BSD_STYLE
  433. X    char *ty;
  434. X    new_mp->mnt_fsname = strdup(mp->f_mntfromname);
  435. X    new_mp->mnt_dir = strdup(mp->f_mntonname);
  436. X    switch (mp->f_type) {
  437. X    case MOUNT_UFS:  ty = MTAB_TYPE_UFS; break;
  438. X    case MOUNT_NFS:  ty = MTAB_TYPE_NFS; break;
  439. X    case MOUNT_MFS:  ty = MTAB_TYPE_MFS; break;
  440. X    default:  ty = "unknown"; break;
  441. X    }
  442. X    new_mp->mnt_type = strdup(ty);
  443. X    new_mp->mnt_opts = strdup("unset");
  444. X    new_mp->mnt_freq = 0;
  445. X    new_mp->mnt_passno = 0;
  446. X#endif
  447. X
  448. X#ifdef READ_MTAB_ULTRIX_STYLE
  449. X    new_mp->mnt_fsname = strdup(mp->fd_devname);
  450. X    new_mp->mnt_dir = strdup(mp->fd_path);
  451. X        if (mp->fd_fstype >= GT_NUMTYPES)
  452. X                mp->fd_fstype = GT_UNKWN;
  453. X        else if (gt_names[mp->fd_fstype] == 0)
  454. X                mp->fd_fstype = GT_UNKWN;
  455. X        new_mp->mnt_type = strdup(gt_names[mp->fd_fstype]);
  456. X    new_mp->mnt_opts = strdup("unset");
  457. X
  458. X    new_mp->mnt_freq = 0;
  459. X    new_mp->mnt_passno = mp->fd_dev;
  460. X#endif
  461. X
  462. X#ifdef READ_MTAB_FROM_FILE
  463. X    new_mp->mnt_fsname = strdup(mp->mnt_fsname);
  464. X    new_mp->mnt_dir = strdup(mp->mnt_dir);
  465. X    new_mp->mnt_type = strdup(mp->mnt_type);
  466. X    new_mp->mnt_opts = strdup(mp->mnt_opts);
  467. X
  468. X    new_mp->mnt_freq = mp->mnt_freq;
  469. X    new_mp->mnt_passno = mp->mnt_passno;
  470. X#endif
  471. X    return new_mp;
  472. X}
  473. X
  474. Xvoid mnt_free(mp)
  475. Xstruct mntent *mp;
  476. X{
  477. X    free(mp->mnt_fsname);
  478. X    free(mp->mnt_dir);
  479. X    free(mp->mnt_type);
  480. X    free(mp->mnt_opts);
  481. X    free((voidp) mp);
  482. X}
  483. X
  484. X/*
  485. X * Read a mount table into memory
  486. X */
  487. X
  488. X#ifdef READ_MTAB_BSD_STYLE
  489. Xmntlist *read_mtab(fs)
  490. Xchar *fs;
  491. X{
  492. X    mntlist **mpp, *mhp;
  493. X    struct statfs *mntbufp, *mntp;
  494. X
  495. X    int nloc = getmntinfo(&mntbufp);
  496. X
  497. X    if (nloc == 0) {
  498. X        plog(XLOG_ERROR, "Can't read mount table");
  499. X        return 0;
  500. X    }
  501. X
  502. X    mpp = &mhp;
  503. X    for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) {
  504. X        /*
  505. X         * Allocate a new slot
  506. X         */
  507. X        *mpp = ALLOC(mntlist);
  508. X
  509. X        /*
  510. X         * Copy the data returned by getmntent
  511. X         */
  512. X        (*mpp)->mnt = mnt_dup(mntp);
  513. X
  514. X        /*
  515. X         * Move to next pointer
  516. X         */
  517. X        mpp = &(*mpp)->mnext;
  518. X    }
  519. X
  520. X    return mhp;
  521. X}
  522. X#endif /* READ_MTAB_BSD_STYLE */
  523. X
  524. X#ifdef READ_MTAB_ULTRIX_STYLE
  525. Xmntlist *read_mtab(fs)
  526. Xchar *fs;
  527. X{
  528. X    mntlist **mpp, *mhp;
  529. X
  530. X/* From: Piete Brooks <pb@cl.cam.ac.uk> */
  531. X
  532. X    int loc=0;
  533. X#undef    NMOUNT
  534. X#define    NMOUNT    20
  535. X    struct fs_data mountbuffer[NMOUNT], *fs_data;
  536. X    int ret;
  537. X
  538. X    mpp = &mhp;
  539. X    while ((ret = getmountent(&loc, mountbuffer, NMOUNT)) > 0) {
  540. X            for (fs_data = mountbuffer; fs_data < &mountbuffer[ret]; fs_data++) {
  541. X            /*
  542. X             * Allocate a new slot
  543. X             */
  544. X            *mpp = ALLOC(mntlist);
  545. X
  546. X            /*
  547. X             * Copy the data returned by getmntent
  548. X             */
  549. X            (*mpp)->mnt = mnt_dup(fs_data);
  550. X
  551. X            /*
  552. X             * Move to next pointer
  553. X             */
  554. X            mpp = &(*mpp)->mnext;
  555. X        }
  556. X    }
  557. X    if (ret < 0) {
  558. X        plog(XLOG_ERROR, "getmountent: %m");
  559. X        return 0;
  560. X    }
  561. X    *mpp = 0;
  562. X
  563. X    return mhp;
  564. X}
  565. X#endif /* READ_MTAB_ULTRIX_STYLE */
  566. X
  567. X#ifdef READ_MTAB_FROM_FILE
  568. Xmntlist *read_mtab(fs)
  569. Xchar *fs;
  570. X{
  571. X    mntlist **mpp, *mhp;
  572. X
  573. X    struct mntent *mep;
  574. X    FILE *mfp = 0;
  575. X
  576. X#ifdef UPDATE_MTAB
  577. X    /*
  578. X     * There is a possible race condition if two processes enter
  579. X     * this routine at the same time.  One will be blocked by the
  580. X     * exclusive lock below (or by the shared lock in setmntent)
  581. X     * and by the time the second process has the exclusive lock
  582. X     * it will be on the wrong underlying object.  To check for this
  583. X     * the mtab file is stat'ed before and after all the locking
  584. X     * sequence, and if it is a different file then we assume that
  585. X     * it may be the wrong file (only "may", since there is another
  586. X     * race between the initial stat and the setmntent).
  587. X     *
  588. X     * Simpler solutions to this problem are invited...
  589. X     */
  590. X    int racing = 0;
  591. X#ifdef MTAB_LOCKING
  592. X    int rc;
  593. X    int retries = 0;
  594. X    struct stat st_before, st_after;
  595. X#endif /* MTAB_LOCKING */
  596. X
  597. X    if (mnt_file) {
  598. X#ifdef DEBUG
  599. X        dlog("Forced close on %s in read_mtab", mtab);
  600. X#endif /* DEBUG */
  601. X        endmntent(mnt_file);
  602. X        mnt_file = 0;
  603. X    }
  604. X
  605. X#ifdef MTAB_LOCKING
  606. Xagain:
  607. X    if (mfp) {
  608. X        endmntent(mfp);
  609. X        mfp = 0;
  610. X    }
  611. X
  612. X    clock_valid = 0;
  613. X    if (stat(mtab, &st_before) < 0) {
  614. X        plog(XLOG_ERROR, "%s: stat: %m", mtab);
  615. X        if (errno == ESTALE) {
  616. X            /* happens occasionally */
  617. X            sleep(1);
  618. X            goto again;
  619. X        }
  620. X        return 0;
  621. X    }
  622. X#endif /* MTAB_LOCKING */
  623. X#endif /* UPDATE_MTAB */
  624. X
  625. Xeacces:
  626. X    mfp = setmntent(mtab, "r+");
  627. X    if (!mfp) {
  628. X        /*
  629. X         * Since setmntent locks the descriptor, it
  630. X         * is possible it can fail... so retry if
  631. X         * needed.
  632. X         */
  633. X        if (errno == EACCES || errno == EAGAIN) {
  634. X#ifdef DEBUG
  635. X            dlog("Blocked, trying to obtain exclusive mtab lock");
  636. X#endif /* DEBUG */
  637. X            goto eacces;
  638. X        } else if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  639. X            sleep(1);
  640. X            goto eacces;
  641. X        }
  642. X
  643. X        plog(XLOG_ERROR, "setmntent(\"%s\", \"r+\"): %m", mtab);
  644. X        return 0;
  645. X    }
  646. X
  647. X#ifdef MTAB_LOCKING
  648. X#ifdef UPDATE_MTAB
  649. X    /*
  650. X     * At this point we have an exclusive lock on the mount list,
  651. X     * but it may be the wrong one so...
  652. X     */
  653. X
  654. X    /*
  655. X     * Need to get an exclusive lock on the current
  656. X     * mount table until we have a new copy written
  657. X     * out, when the lock is released in free_mntlist.
  658. X     * flock is good enough since the mount table is
  659. X     * not shared between machines.
  660. X     */
  661. X    do
  662. X        rc = lock(fileno(mfp));
  663. X    while (rc < 0 && errno == EINTR);
  664. X    if (rc < 0) {
  665. X        plog(XLOG_ERROR, "Couldn't lock %s: %m", mtab);
  666. X        endmntent(mfp);
  667. X        return 0;
  668. X    }
  669. X    /*
  670. X     * Now check whether the mtab file has changed under our feet
  671. X     */
  672. X    if (stat(mtab, &st_after) < 0) {
  673. X        plog(XLOG_ERROR, "%s: stat", mtab);
  674. X        goto again;
  675. X    }
  676. X
  677. X    if (st_before.st_dev != st_after.st_dev ||
  678. X        st_before.st_ino != st_after.st_ino) {
  679. X            if (racing == 0) {
  680. X                /* Sometimes print a warning */
  681. X                plog(XLOG_WARNING,
  682. X                    "Possible mount table race - retrying %s", fs);
  683. X            }
  684. X            racing = (racing+1) & 3;
  685. X            goto again;
  686. X    }
  687. X#endif /* UPDATE_MTAB */
  688. X#endif /* MTAB_LOCKING */
  689. X
  690. X    mpp = &mhp;
  691. X
  692. X/*
  693. X * XXX - In SunOS 4 there is (yet another) memory leak
  694. X * which loses 1K the first time getmntent is called.
  695. X * (jsp)
  696. X */
  697. X    while (mep = getmntent(mfp)) {
  698. X        /*
  699. X         * Allocate a new slot
  700. X         */
  701. X        *mpp = ALLOC(mntlist);
  702. X
  703. X        /*
  704. X         * Copy the data returned by getmntent
  705. X         */
  706. X        (*mpp)->mnt = mnt_dup(mep);
  707. X
  708. X        /*
  709. X         * Move to next pointer
  710. X         */
  711. X        mpp = &(*mpp)->mnext;
  712. X    }
  713. X    *mpp = 0;
  714. X
  715. X#ifdef UPDATE_MTAB
  716. X    /*
  717. X     * If we are not updating the mount table then we
  718. X     * can free the resources held here, otherwise they
  719. X     * must be held until the mount table update is complete
  720. X     */
  721. X    mnt_file = mfp;
  722. X#else
  723. X    endmntent(mfp);
  724. X#endif /* UPDATE_MTAB */
  725. X
  726. X    return mhp;
  727. X}
  728. X#endif /* READ_MTAB_FROM_FILE */
  729. X
  730. X/*
  731. X * Throw away a mount list
  732. X */
  733. Xvoid free_mntlist(mp)
  734. Xmntlist *mp;
  735. X{
  736. X    mntlist *mp2;
  737. X
  738. X    while (mp2 = mp) {
  739. X        mp = mp->mnext;
  740. X        if (mp2->mnt)
  741. X            mnt_free(mp2->mnt);
  742. X        free(mp2);
  743. X    }
  744. X
  745. X#ifdef UPDATE_MTAB
  746. X    /*
  747. X     * Release file lock, by closing the file
  748. X     */
  749. X    if (mnt_file) {
  750. X        endmntent(mnt_file);
  751. X        mnt_file = 0;
  752. X    }
  753. X#endif /* UPDATE_MTAB */
  754. X}
  755. X
  756. X#ifdef UPDATE_MTAB
  757. X/*
  758. X * Write out a mount list
  759. X */
  760. Xvoid rewrite_mtab(mp)
  761. Xmntlist *mp;
  762. X{
  763. X    FILE *mfp;
  764. X
  765. X    /*
  766. X     * Concoct a temporary name in the same
  767. X     * directory as the target mount table
  768. X     * so that rename() will work.
  769. X     */
  770. X    char tmpname[64];
  771. X    int retries;
  772. X    int tmpfd;
  773. X    char *cp;
  774. X    char *mcp = mtab;
  775. X    cp = strrchr(mcp, '/');
  776. X    if (cp) {
  777. X        bcopy(mcp, tmpname, cp - mcp);
  778. X        tmpname[cp-mcp] = '\0';
  779. X    } else {
  780. X        plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mtab);
  781. X        tmpname[0] = '.'; tmpname[1] = '\0';
  782. X    }
  783. X    strcat(tmpname, "/mtabXXXXXX");
  784. X    mktemp(tmpname);
  785. X    retries = 0;
  786. Xenfile1:
  787. X    if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
  788. X        if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  789. X            sleep(1);
  790. X            goto enfile1;
  791. X        }
  792. X        plog(XLOG_ERROR, "%s: open: %m", tmpname);
  793. X        return;
  794. X    }
  795. X    if (close(tmpfd) < 0)
  796. X        plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");
  797. X
  798. X    retries = 0;
  799. Xenfile2:
  800. X    mfp = setmntent(tmpname, "w");
  801. X    if (!mfp) {
  802. X        if (errno == ENFILE && retries++ < NFILE_RETRIES) {
  803. X            sleep(1);
  804. X            goto enfile2;
  805. X        }
  806. X        plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
  807. X        return;
  808. X    }
  809. X
  810. X    while (mp) {
  811. X        if (mp->mnt)
  812. X            if (addmntent(mfp, mp->mnt))
  813. X                plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
  814. X        mp = mp->mnext;
  815. X    }
  816. X
  817. X    endmntent(mfp);
  818. X
  819. X    /*
  820. X     * Rename temporary mtab to real mtab
  821. X     */
  822. X    if (rename(tmpname, mtab) < 0)
  823. X        plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
  824. X}
  825. X
  826. X/*
  827. X * Append a mntent structure to the
  828. X * current mount table.
  829. X */
  830. Xvoid write_mntent(mp)
  831. Xstruct mntent *mp;
  832. X{
  833. X    int retries = 0;
  834. X    FILE *mfp;
  835. Xenfile:
  836. X    mfp = setmntent(mtab, "a");
  837. X    if (mfp) {
  838. X#ifdef MTAB_STRIPNL
  839. X        mtab_stripnl(mp->mnt_opts);
  840. X#endif /* MTAB_STRIPNL */
  841. X        if (addmntent(mfp, mp))
  842. X            plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
  843. X        endmntent(mfp);
  844. X    } else {
  845. X        if (errno == ENFILE && retries < NFILE_RETRIES) {
  846. X            sleep(1);
  847. X            goto enfile;
  848. X        }
  849. X        plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mtab);
  850. X    }
  851. X}
  852. X#endif /* UPDATE_MTAB */
  853. X
  854. X/*
  855. X * Utility routine which determines the value of a
  856. X * numeric option in the mount options (such as port=%d).
  857. X * Returns 0 if the option is not specified.
  858. X */
  859. Xint hasmntval(mnt, opt)
  860. Xstruct mntent *mnt;
  861. Xchar *opt;
  862. X{
  863. X    char *str = hasmntopt(mnt, opt);
  864. X    if (str) {
  865. X        char *eq = strchr(str, '=');
  866. X        if (eq)
  867. X            return atoi(eq+1);
  868. X        else
  869. X            plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str);
  870. X    }
  871. X
  872. X    return 0;
  873. X}
  874. END_OF_FILE
  875. if test 12010 -ne `wc -c <'mtab.c'`; then
  876.     echo shar: \"'mtab.c'\" unpacked with wrong size!
  877. fi
  878. # end of 'mtab.c'
  879. fi
  880. if test -f 'opts.c' -a "${1}" != "-c" ; then 
  881.   echo shar: Will not clobber existing file \"'opts.c'\"
  882. else
  883. echo shar: Extracting \"'opts.c'\" \(14812 characters\)
  884. sed "s/^X//" >'opts.c' <<'END_OF_FILE'
  885. X/*
  886. X * $Id: opts.c,v 5.1 89/11/17 18:21:43 jsp Exp Locker: jsp $
  887. X *
  888. X * Copyright (c) 1989 Jan-Simon Pendry
  889. X * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
  890. X * Copyright (c) 1989 The Regents of the University of California.
  891. X * All rights reserved.
  892. X *
  893. X * This code is derived from software contributed to Berkeley by
  894. X * Jan-Simon Pendry at Imperial College, London.
  895. X *
  896. X * Redistribution and use in source and binary forms are permitted
  897. X * provided that the above copyright notice and this paragraph are
  898. X * duplicated in all such forms and that any documentation,
  899. X * advertising materials, and other materials related to such
  900. X * distribution and use acknowledge that the software was developed
  901. X * by Imperial College of Science, Technology and Medicine, London, UK.
  902. X * The names of the College and University may not be used to endorse
  903. X * or promote products derived from this software without specific
  904. X * prior written permission.
  905. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  906. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  907. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  908. X *
  909. X *    %W% (Berkeley) %G%
  910. X */
  911. X
  912. X#include "am.h"
  913. X
  914. Xextern char *getenv P((char *));
  915. X
  916. X/*
  917. X * static copy of the options with
  918. X * which to play
  919. X */
  920. Xstatic struct am_opts fs_static;
  921. X
  922. Xstatic char *opt_host = hostname;
  923. Xstatic char *opt_hostd = hostd;
  924. Xstatic char nullstr[] = "";
  925. Xstatic char *opt_key = nullstr;
  926. Xstatic char *opt_map = nullstr;
  927. Xstatic char *opt_path = nullstr;
  928. X
  929. X/*
  930. X * Length of longest option name
  931. X */
  932. X#define    NLEN    16
  933. X#define S(x) (x) , (sizeof(x)-1)
  934. Xstatic struct opt {
  935. X    char *name;        /* Name of the option */
  936. X    int nlen;        /* Length of option name */
  937. X    char **optp;        /* Pointer to option value string */
  938. X    char **sel_p;        /* Pointer to selector value string */
  939. X} opt_fields[] = {
  940. X    /* Options in something corresponding to frequency of use */
  941. X    { S("opts"), &fs_static.opt_opts, 0 },
  942. X    { S("host"), 0, &opt_host },
  943. X    { S("hostd"), 0, &opt_hostd },
  944. X    { S("type"), &fs_static.opt_type, 0 },
  945. X    { S("rhost"), &fs_static.opt_rhost, 0 },
  946. X    { S("rfs"), &fs_static.opt_rfs, 0 },
  947. X    { S("fs"), &fs_static.opt_fs, 0 },
  948. X    { S("key"), 0, &opt_key },
  949. X    { S("map"), 0, &opt_map },
  950. X    { S("sublink"), &fs_static.opt_sublink, 0 },
  951. X    { S("arch"), 0, &arch },
  952. X    { S("dev"), &fs_static.opt_dev, 0 },
  953. X    { S("pref"), &fs_static.opt_pref, 0 },
  954. X    { S("path"), 0, &opt_path },
  955. X    { S("autodir"), 0, &auto_dir },
  956. X    { S("delay"), &fs_static.opt_delay, 0 },
  957. X    { S("domain"), 0, &hostdomain },
  958. X    { S("karch"), 0, &karch },
  959. X    { S("cluster"), 0, &cluster },
  960. X    { S("byte"), 0, &endian },
  961. X    { S("os"), 0, &op_sys },
  962. X    { S("mount"), &fs_static.opt_mount, 0 },
  963. X    { S("unmount"), &fs_static.opt_unmount, 0 },
  964. X    { S("cache"), &fs_static.opt_cache, 0 },
  965. X    { S("user"), &fs_static.opt_user, 0 },
  966. X    { S("group"), &fs_static.opt_group, 0 },
  967. X    { 0, 0, 0, 0 },
  968. X};
  969. X
  970. Xtypedef struct opt_apply opt_apply;
  971. Xstruct opt_apply {
  972. X    char **opt;
  973. X    char *val;
  974. X};
  975. X
  976. X/*
  977. X * Specially expand the remote host name first
  978. X */
  979. Xstatic opt_apply rhost_expansion[] = {
  980. X    { &fs_static.opt_rhost, "${host}" },
  981. X    { 0, 0 },
  982. X};
  983. X/*
  984. X * List of options which need to be expanded
  985. X * Note that this the order here _may_ be important.
  986. X */
  987. Xstatic opt_apply expansions[] = {
  988. X/*    { &fs_static.opt_dir, 0 },    */
  989. X    { &fs_static.opt_sublink, 0 },
  990. X    { &fs_static.opt_rfs, "${path}" },
  991. X    { &fs_static.opt_fs, "${autodir}/${rhost}${rfs}" },
  992. X    { &fs_static.opt_opts, "rw" },
  993. X    { &fs_static.opt_mount, 0 },
  994. X    { &fs_static.opt_unmount, 0 },
  995. X    { 0, 0 },
  996. X};
  997. X
  998. X/*
  999. X * List of options which need to be free'ed before re-use
  1000. X */
  1001. Xstatic opt_apply to_free[] = {
  1002. X    { &fs_static.fs_glob, 0 },
  1003. X    { &fs_static.fs_local, 0 },
  1004. X    { &fs_static.fs_mtab, 0 },
  1005. X/*    { &fs_static.opt_dir, 0 },    */
  1006. X    { &fs_static.opt_sublink, 0 },
  1007. X    { &fs_static.opt_rfs, 0 },
  1008. X    { &fs_static.opt_fs, 0 },
  1009. X    { &fs_static.opt_rhost, 0 },
  1010. X    { &fs_static.opt_opts, 0 },
  1011. X    { &fs_static.opt_mount, 0 },
  1012. X    { &fs_static.opt_unmount, 0 },
  1013. X    { 0, 0 },
  1014. X};
  1015. X
  1016. X/*
  1017. X * Skip to next option in the string
  1018. X */
  1019. Xstatic char *opt P((char**));
  1020. Xstatic char *opt(p)
  1021. Xchar **p;
  1022. X{
  1023. X    char *cp = *p;
  1024. X    char *dp = cp;
  1025. X    char *s = cp;
  1026. X
  1027. Xtop:
  1028. X    while (*cp && *cp != ';') {
  1029. X        if (*cp == '\"') {
  1030. X            /*
  1031. X             * Skip past string
  1032. X             */
  1033. X            cp++;
  1034. X            while (*cp && *cp != '\"')
  1035. X                *dp++ = *cp++;
  1036. X            if (*cp)
  1037. X                cp++;
  1038. X        } else {
  1039. X            *dp++ = *cp++;
  1040. X        }
  1041. X    }
  1042. X
  1043. X    /*
  1044. X     * Skip past any remaining ';'s
  1045. X     */
  1046. X    while (*cp == ';')
  1047. X        cp++;
  1048. X
  1049. X    /*
  1050. X     * If we have a zero length string
  1051. X     * and there are more fields, then
  1052. X     * parse the next one.  This allows
  1053. X     * sequences of empty fields.
  1054. X     */
  1055. X    if (*cp && dp == s)
  1056. X        goto top;
  1057. X
  1058. X    *dp = '\0';
  1059. X
  1060. X    *p = cp;
  1061. X    return s;
  1062. X}
  1063. X
  1064. Xstatic int eval_opts P((char*));
  1065. Xstatic int eval_opts(opts)
  1066. Xchar *opts;
  1067. X{
  1068. X    /*
  1069. X     * Fill in the global structure fs_static by
  1070. X     * cracking the string opts.  opts may be
  1071. X     * scribbled on at will.
  1072. X     */
  1073. X    char *o = opts;
  1074. X    char *f;
  1075. X
  1076. X    /*
  1077. X     * For each user-specified option
  1078. X     */
  1079. X    while (*(f = opt(&o))) {
  1080. X        struct opt *op;
  1081. X        enum vs_opt { OldSyn, SelEQ, SelNE, VarAss } vs_opt;
  1082. X        char *eq = strchr(f, '=');
  1083. X        char *opt;
  1084. X        if (!eq || eq[1] == '\0' || eq == f) {
  1085. X            /*
  1086. X             * No value, just continue
  1087. X             */
  1088. X            plog(XLOG_USER, "No value component in \"%s\"", f);
  1089. X            continue;
  1090. X        }
  1091. X
  1092. X        /*
  1093. X         * Check what type of operation is happening
  1094. X         * !=, =!  is SelNE
  1095. X         * == is SelEQ
  1096. X         * := is VarAss
  1097. X         * = is OldSyn (either SelEQ or VarAss)
  1098. X         */
  1099. X        if (eq[-1] == '!') {        /* != */
  1100. X            vs_opt = SelNE;
  1101. X            eq[-1] = '\0';
  1102. X            opt = eq + 1;
  1103. X        } else if (eq[-1] == ':') {    /* := */
  1104. X            vs_opt = VarAss;
  1105. X            eq[-1] = '\0';
  1106. X            opt = eq + 1;
  1107. X        } else if (eq[1] == '=') {    /* == */
  1108. X            vs_opt = SelEQ;
  1109. X            eq[0] = '\0';
  1110. X            opt = eq + 2;
  1111. X        } else if (eq[1] == '!') {    /* =! */
  1112. X            vs_opt = SelNE;
  1113. X            eq[0] = '\0';
  1114. X            opt = eq + 2;
  1115. X        } else {            /* = */
  1116. X            vs_opt = OldSyn;
  1117. X            eq[0] = '\0';
  1118. X            opt = eq + 1;
  1119. X        }
  1120. X
  1121. X        /*
  1122. X         * For each recognised option
  1123. X         */
  1124. X        for (op = opt_fields; op->name; op++) {
  1125. X            /*
  1126. X             * Check whether they match
  1127. X             */
  1128. X            if (FSTREQ(op->name, f)) {
  1129. X                switch (vs_opt) {
  1130. X#if AMD_COMPAT <= 5000108
  1131. X                case OldSyn:
  1132. X                    if (!op->sel_p) {
  1133. X                        *op->optp = opt;
  1134. X                        break;
  1135. X                    }
  1136. X                    /* fall through ... */
  1137. X#endif /* 5000108 */
  1138. X                case SelEQ:
  1139. X                case SelNE:
  1140. X                    if (op->sel_p && (STREQ(*op->sel_p, opt) == (vs_opt == SelNE))) {
  1141. X                        plog(XLOG_MAP, "map selector %s (=%s) did not %smatch %s",
  1142. X                            op->name,
  1143. X                            *op->sel_p,
  1144. X                            vs_opt == SelNE ? "not " : "",
  1145. X                            opt);
  1146. X                        return 0;
  1147. X                    }
  1148. X                    break;
  1149. X
  1150. X                case VarAss:
  1151. X                    if (op->sel_p) {
  1152. X                        plog(XLOG_USER, "Can't assign to a selector (%s)", op->name);
  1153. X                        return 0;
  1154. X                    }
  1155. X                    *op->optp = opt;
  1156. X                    break;
  1157. X                }
  1158. X                break;
  1159. X            }
  1160. X        }
  1161. X
  1162. X        if (!op->name)
  1163. X            plog(XLOG_USER, "Unrecognised key \"%s\"", f);
  1164. X    }
  1165. X
  1166. X    return 1;
  1167. X}
  1168. X
  1169. X/*
  1170. X * Free an option
  1171. X */
  1172. Xstatic void free_op P((opt_apply*, int));
  1173. X/*ARGSUSED*/
  1174. Xstatic void free_op(p, b)
  1175. Xopt_apply *p;
  1176. Xint b;
  1177. X{
  1178. X    if (*p->opt) {
  1179. X        free(*p->opt);
  1180. X        *p->opt = 0;
  1181. X    }
  1182. X}
  1183. X
  1184. X/*
  1185. X * Macro-expand an option.  Note that this does not
  1186. X * handle recursive expansions.  They will go badly wrong.
  1187. X * If sel is true then old expand selectors, otherwise
  1188. X * don't expand selectors.
  1189. X */
  1190. Xstatic void expand_op P((opt_apply*, int));
  1191. Xstatic void expand_op(p, sel_p)
  1192. Xopt_apply *p;
  1193. Xint sel_p;
  1194. X{
  1195. X/*
  1196. X * The BUFSPACE macros checks that there is enough space
  1197. X * left in the expansion buffer.  If there isn't then we
  1198. X * give up completely.  This is done to avoid crashing the
  1199. X * automounter itself (which would be a bad thing to do).
  1200. X */
  1201. X#define BUFSPACE(ep, len) (((ep) + (len)) < expbuf+MAXPATHLEN)
  1202. Xstatic char expand_error[] = "No space to expand \"%s\"";
  1203. X
  1204. X    char expbuf[MAXPATHLEN];
  1205. X    char nbuf[NLEN+1];
  1206. X    char *ep = expbuf;
  1207. X    char *cp = *p->opt;
  1208. X    char *dp;
  1209. X#ifdef DEBUG
  1210. X    char *cp_orig = *p->opt;
  1211. X#endif
  1212. X    struct opt *op;
  1213. X
  1214. X    while (dp = strchr(cp, '$')) {
  1215. X        char ch;
  1216. X        /*
  1217. X         * First copy up to the $
  1218. X         */
  1219. X        { int len = dp - cp;
  1220. X          if (BUFSPACE(ep, len)) {
  1221. X            strncpy(ep, cp, len);
  1222. X            ep += len;
  1223. X          } else {
  1224. X            plog(XLOG_ERROR, expand_error, *p->opt);
  1225. X            goto out;
  1226. X          }
  1227. X        }
  1228. X        cp = dp + 1;
  1229. X        ch = *cp++;
  1230. X        if (ch == '$') {
  1231. X            if (BUFSPACE(ep, 1)) {
  1232. X                *ep++ = '$';
  1233. X            } else {
  1234. X                plog(XLOG_ERROR, expand_error, *p->opt);
  1235. X                goto out;
  1236. X            }
  1237. X        } else if (ch == '{') {
  1238. X            /* Expansion... */
  1239. X            enum { E_All, E_Dir, E_File } todo;
  1240. X            /*
  1241. X             * Find closing brace
  1242. X             */
  1243. X            char *br_p = strchr(cp, '}');
  1244. X            int len;
  1245. X            /*
  1246. X             * Check we found it
  1247. X             */
  1248. X            if (!br_p) {
  1249. X                /*
  1250. X                 * Just give up
  1251. X                 */
  1252. X                plog(XLOG_USER, "No closing '}' in \"%s\"", *p->opt);
  1253. X                goto out;
  1254. X            }
  1255. X            len = br_p - cp;
  1256. X            /*
  1257. X             * Figure out which part of the variable to grab.
  1258. X             */
  1259. X            if (*cp == '/') {
  1260. X                /*
  1261. X                 * Just take the last component
  1262. X                 */
  1263. X                todo = E_File;
  1264. X                cp++;
  1265. X                --len;
  1266. X            } else if (br_p[-1] == '/') {
  1267. X                /*
  1268. X                 * Take all but the last component
  1269. X                 */
  1270. X                todo = E_Dir;
  1271. X                --len;
  1272. X            } else {
  1273. X                /*
  1274. X                 * Take the whole lot
  1275. X                 */
  1276. X                todo = E_All;
  1277. X            }
  1278. X            /*
  1279. X             * Truncate if too long.  Since it won't
  1280. X             * match anyway it doesn't matter that
  1281. X             * it has been cut short.
  1282. X             */
  1283. X            if (len > NLEN)
  1284. X                len = NLEN;
  1285. X            /*
  1286. X             * Put the string into another buffer so
  1287. X             * we can do comparisons.
  1288. X             */
  1289. X            strncpy(nbuf, cp, len);
  1290. X            nbuf[len] = '\0';
  1291. X            /*
  1292. X             * Advance cp
  1293. X             */
  1294. X            cp = br_p + 1;
  1295. X            /*
  1296. X             * Search the option array
  1297. X             */
  1298. X            for (op = opt_fields; op->name; op++) {
  1299. X                /*
  1300. X                 * Check for match
  1301. X                 */
  1302. X                if (len == op->nlen && STREQ(op->name, nbuf)) {
  1303. X                    char xbuf[NLEN+3];
  1304. X                    char *val;
  1305. X                    /*
  1306. X                     * Found expansion.  Copy
  1307. X                     * the correct value field.
  1308. X                     */
  1309. X                    if (!(!op->sel_p == !sel_p)) {
  1310. X                        /*
  1311. X                         * Copy the string across unexpanded
  1312. X                         */
  1313. X                        sprintf(xbuf, "${%s%s%s}",
  1314. X                            todo == E_File ? "/" : "",
  1315. X                            nbuf,
  1316. X                            todo == E_Dir ? "/" : "");
  1317. X                        val = xbuf;
  1318. X                    } else if (op->sel_p) {
  1319. X                        val = *op->sel_p;
  1320. X                    } else {
  1321. X                        val = *op->optp;
  1322. X                    }
  1323. X                    if (val) {
  1324. X                        /*
  1325. X                         * Do expansion:
  1326. X                         * ${/var} means take just the last part
  1327. X                         * ${var/} means take all but the last part
  1328. X                         * ${var} means take the whole lot
  1329. X                         */
  1330. X                        int vlen = strlen(val);
  1331. X                        char *vptr = val;
  1332. X                        switch (todo) {
  1333. X                        case E_Dir:
  1334. X                            vptr = strchr(val, '/');
  1335. X                            if (vptr)
  1336. X                                vlen = vptr - val;
  1337. X                            vptr = val;
  1338. X                            break;
  1339. X                        case E_File:
  1340. X                            vptr = strchr(val, '/');
  1341. X                            if (vptr) {
  1342. X                                vptr++;
  1343. X                                vlen = strlen(vptr);
  1344. X                            }
  1345. X                            break;
  1346. X                        }
  1347. X#ifdef DEBUG
  1348. X                    /*dlog("Expanding \"%s\" to \"%s\"", nbuf, val);*/
  1349. X#endif
  1350. X                        if (BUFSPACE(ep, vlen)) {
  1351. X                            strcpy(ep, vptr);
  1352. X                            ep += vlen;
  1353. X                        } else {
  1354. X                            plog(XLOG_ERROR, expand_error, *p->opt);
  1355. X                            goto out;
  1356. X                        }
  1357. X                    }
  1358. X                    /*
  1359. X                     * Done with this variable
  1360. X                     */
  1361. X                    break;
  1362. X                }
  1363. X            }
  1364. X            /*
  1365. X             * Check that the search was succesful
  1366. X             */
  1367. X            if (!op->name) {
  1368. X                /*
  1369. X                 * If it wasn't then scan the
  1370. X                 * environment for that name
  1371. X                 * and use any value found
  1372. X                 */
  1373. X                char *env = getenv(nbuf);
  1374. X                if (env) {
  1375. X                    int vlen = strlen(env);
  1376. X
  1377. X                    if (BUFSPACE(ep, vlen)) {
  1378. X                        strcpy(ep, env);
  1379. X                        ep += vlen;
  1380. X                    } else {
  1381. X                        plog(XLOG_ERROR, expand_error, *p->opt);
  1382. X                        goto out;
  1383. X                    }
  1384. X#ifdef DEBUG
  1385. X                    Debug(D_STR)
  1386. X                    plog(XLOG_DEBUG, "Environment gave \"%s\" -> \"%s\"", nbuf, env);
  1387. X#endif
  1388. X                } else {
  1389. X                    plog(XLOG_USER, "Unknown sequence \"${%s}\"", nbuf);
  1390. X                }
  1391. X            }
  1392. X        } else {
  1393. X            /*
  1394. X             * Error, error
  1395. X             */
  1396. X            plog(XLOG_USER, "Unknown $ sequence in \"%s\"", *p->opt);
  1397. X        }
  1398. X    }
  1399. X
  1400. Xout:
  1401. X    /*
  1402. X     * Handle common case - no expansion
  1403. X     */
  1404. X    if (cp == *p->opt) {
  1405. X        *p->opt = strdup(cp);
  1406. X    } else {
  1407. X        /*
  1408. X         * Finish off the expansion
  1409. X         */
  1410. X        if (BUFSPACE(ep, strlen(cp))) {
  1411. X            strcpy(ep, cp);
  1412. X            /*ep += strlen(ep);*/
  1413. X        } else {
  1414. X            plog(XLOG_ERROR, expand_error, *p->opt);
  1415. X        }
  1416. X
  1417. X        /*
  1418. X         * Save the exansion
  1419. X         */
  1420. X        *p->opt = strdup(expbuf);
  1421. X    }
  1422. X
  1423. X    /*
  1424. X     * Normalize slashes in the string.
  1425. X     */
  1426. X    { char *f = strchr(*p->opt, '/');
  1427. X      if (f) {
  1428. X        char *t = f;
  1429. X        do {
  1430. X            /* assert(*f == '/'); */
  1431. X            /* copy a single / across */
  1432. X            *t++ = *f++;
  1433. X
  1434. X            /* assert(f[-1] == '/'); */
  1435. X            /* skip past more /'s */
  1436. X            while (*f == '/')
  1437. X                f++;
  1438. X
  1439. X            /* assert(*f != '/'); */
  1440. X            /* keep copying up to next / */
  1441. X            do {
  1442. X                *t++ = *f++;
  1443. X            } while (*f && *f != '/');
  1444. X
  1445. X            /* assert(*f == 0 || *f == '/'); */
  1446. X
  1447. X        } while (*f);
  1448. X      }
  1449. X    }
  1450. X      
  1451. X#ifdef DEBUG
  1452. X    Debug(D_STR) {
  1453. X        plog(XLOG_DEBUG, "Expansion of \"%s\"...", cp_orig);
  1454. X        plog(XLOG_DEBUG, "... is \"%s\"", *p->opt);
  1455. X    }
  1456. X#endif
  1457. X}
  1458. X
  1459. X/*
  1460. X * Wrapper for expand_op
  1461. X */
  1462. Xstatic void expand_opts P((opt_apply*, int));
  1463. Xstatic void expand_opts(p, sel_p)
  1464. Xopt_apply *p;
  1465. Xint sel_p;
  1466. X{
  1467. X    if (*p->opt) {
  1468. X        expand_op(p, sel_p);
  1469. X    } else if (p->val) {
  1470. X        /*
  1471. X         * Do double expansion, remembering
  1472. X         * to free the string from the first
  1473. X         * expansion...
  1474. X         */
  1475. X        char *s = *p->opt = expand_key(p->val);
  1476. X        expand_op(p, sel_p);
  1477. X        free(s);
  1478. X    }
  1479. X}
  1480. X
  1481. X/*
  1482. X * Apply a function to a list of options
  1483. X */
  1484. Xstatic void apply_opts(op, ppp, b)
  1485. Xvoid (*op)();
  1486. Xopt_apply ppp[];
  1487. Xint b;
  1488. X{
  1489. X    opt_apply *pp;
  1490. X    for (pp = ppp; pp->opt; pp++)
  1491. X        (*op)(pp, b);
  1492. X}
  1493. X
  1494. X/*
  1495. X * Free the option table
  1496. X */
  1497. Xvoid free_opts(fo)
  1498. Xam_opts *fo;
  1499. X{
  1500. X    /*
  1501. X     * Copy in the structure we are playing with
  1502. X     */
  1503. X    fs_static = *fo;
  1504. X
  1505. X    /*
  1506. X     * Free previously allocated memory
  1507. X     */
  1508. X    apply_opts(free_op, to_free, FALSE);
  1509. X}
  1510. X
  1511. X/*
  1512. X * Expand lookup key
  1513. X */
  1514. Xchar *expand_key(key)
  1515. Xchar *key;
  1516. X{
  1517. X    opt_apply oa;
  1518. X
  1519. X    oa.opt = &key; oa.val = 0;
  1520. X    expand_opts(&oa, TRUE);
  1521. X
  1522. X    return key;
  1523. X}
  1524. X
  1525. Xint eval_fs_opts(fo, opts, g_opts, path, key, map)
  1526. Xam_opts *fo;
  1527. Xchar *opts, *g_opts, *path, *key, *map;
  1528. X{
  1529. X    int ok = TRUE;
  1530. X
  1531. X    free_opts(fo);
  1532. X
  1533. X    /*
  1534. X     * Clear out the option table
  1535. X     */
  1536. X    bzero((voidp) &fs_static, sizeof(fs_static));
  1537. X    bzero((voidp) fo, sizeof(*fo));
  1538. X
  1539. X    /*
  1540. X     * Set key before expansion
  1541. X     */
  1542. X    opt_key = key;
  1543. X    opt_map = map;
  1544. X    opt_path = path;
  1545. X
  1546. X    /*
  1547. X     * Expand global options
  1548. X     */
  1549. X    fs_static.fs_glob = expand_key(g_opts);
  1550. X
  1551. X    /*
  1552. X     * Expand local options
  1553. X     */
  1554. X    fs_static.fs_local = expand_key(opts);
  1555. X
  1556. X    /*
  1557. X     * Expand default (global) options
  1558. X     */
  1559. X    if (!eval_opts(fs_static.fs_glob))
  1560. X        ok = FALSE;
  1561. X
  1562. X    /*
  1563. X     * Expand local options
  1564. X     */
  1565. X    if (ok && !eval_opts(fs_static.fs_local))
  1566. X        ok = FALSE;
  1567. X
  1568. X    /*
  1569. X     * Normalise remote host name.
  1570. X     * 1.  Expand variables
  1571. X     * 2.  Normalize relative to host tables
  1572. X     * 3.  Strip local domains from the remote host
  1573. X     *     name before using it in other expansions.
  1574. X     *     This makes mount point names and other things
  1575. X     *     much shorter, while allowing cross domain
  1576. X     *     sharing of mount maps.
  1577. X     */
  1578. X    apply_opts(expand_opts, rhost_expansion, FALSE);
  1579. X    if (ok && fs_static.opt_rhost && *fs_static.opt_rhost)
  1580. X        host_normalize(&fs_static.opt_rhost);
  1581. X
  1582. X    /*
  1583. X     * Macro expand the options.
  1584. X     * Do this regardless of whether we are accepting
  1585. X     * this mount - otherwise nasty things happen
  1586. X     * with memory allocation.
  1587. X     */
  1588. X    apply_opts(expand_opts, expansions, FALSE);
  1589. X
  1590. X    /*
  1591. X     * ok... copy the data back out.
  1592. X     */
  1593. X    *fo = fs_static;
  1594. X
  1595. X    /*
  1596. X     * Clear defined options
  1597. X     */
  1598. X    opt_key = opt_map = opt_path = nullstr;
  1599. X
  1600. X    return ok;
  1601. X}
  1602. END_OF_FILE
  1603. if test 14812 -ne `wc -c <'opts.c'`; then
  1604.     echo shar: \"'opts.c'\" unpacked with wrong size!
  1605. fi
  1606. # end of 'opts.c'
  1607. fi
  1608. if test -f 'srvr_nfs.c' -a "${1}" != "-c" ; then 
  1609.   echo shar: Will not clobber existing file \"'srvr_nfs.c'\"
  1610. else
  1611. echo shar: Extracting \"'srvr_nfs.c'\" \(11929 characters\)
  1612. sed "s/^X//" >'srvr_nfs.c' <<'END_OF_FILE'
  1613. X/*
  1614. X * $Id: srvr_nfs.c,v 5.1.1.2 90/01/11 17:21:08 jsp Exp Locker: jsp $
  1615. X *
  1616. X * Copyright (c) 1990 Jan-Simon Pendry
  1617. X * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  1618. X * Copyright (c) 1990 The Regents of the University of California.
  1619. X * All rights reserved.
  1620. X *
  1621. X * This code is derived from software contributed to Berkeley by
  1622. X * Jan-Simon Pendry at Imperial College, London.
  1623. X *
  1624. X * Redistribution and use in source and binary forms are permitted
  1625. X * provided that the above copyright notice and this paragraph are
  1626. X * duplicated in all such forms and that any documentation,
  1627. X * advertising materials, and other materials related to such
  1628. X * distribution and use acknowledge that the software was developed
  1629. X * by Imperial College of Science, Technology and Medicine, London, UK.
  1630. X * The names of the College and University may not be used to endorse
  1631. X * or promote products derived from this software without specific
  1632. X * prior written permission.
  1633. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1634. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1635. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1636. X *
  1637. X *    %W% (Berkeley) %G%
  1638. X */
  1639. X
  1640. X/*
  1641. X * NFS server modeling
  1642. X */
  1643. X
  1644. X#include "am.h"
  1645. X#include <netdb.h>
  1646. X#include <rpc/pmap_prot.h>
  1647. X#include "mount.h"
  1648. X
  1649. Xextern qelem nfs_srvr_list;
  1650. Xqelem nfs_srvr_list = { &nfs_srvr_list, &nfs_srvr_list };
  1651. X
  1652. Xtypedef struct nfs_private {
  1653. X    u_short np_mountd;    /* Mount daemon port number */
  1654. X    int np_ping;        /* Number of failed ping attempts */
  1655. X    int np_xid;        /* RPC transaction id for pings */
  1656. X    int np_error;        /* Error during portmap request */
  1657. X} nfs_private;
  1658. X
  1659. Xstatic int np_xid;    /* For NFS pings */
  1660. X#define    NPXID_ALLOC()    (++np_xid)
  1661. X/*#define    NPXID_ALLOC()    ((++np_xid&0x0fffffff) == 0 ? npxid_gc() : np_xid)*/
  1662. X
  1663. X/*
  1664. X * Number of pings allowed to fail before host is declared down
  1665. X * - three-fifths of the allowed mount time...
  1666. X */
  1667. X#define    MAX_ALLOWED_PINGS    ((((ALLOWED_MOUNT_TIME + 5 * AM_PINGER - 1) * 3) / 5) / AM_PINGER)
  1668. X/*
  1669. X * How often to ping when starting a new server
  1670. X */
  1671. X#define    FAST_NFS_PING        3
  1672. X
  1673. Xstatic int ping_len;
  1674. Xstatic char ping_buf[sizeof(struct rpc_msg) + 32];
  1675. X
  1676. X/*
  1677. X * Startup the NFS ping
  1678. X */
  1679. Xstatic void start_ping()
  1680. X{
  1681. X    XDR ping_xdr;
  1682. X    struct rpc_msg ping_msg;
  1683. X
  1684. X    rpc_msg_init(&ping_msg, NFS_PROGRAM, NFS_VERSION, NFSPROC_NULL);
  1685. X
  1686. X    /*
  1687. X     * Create an XDR endpoint
  1688. X     */
  1689. X    xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE);
  1690. X
  1691. X    /*
  1692. X     * Create the NFS ping message
  1693. X     */
  1694. X    if (!xdr_callmsg(&ping_xdr, &ping_msg)) {
  1695. X        plog(XLOG_ERROR, "Couldn't create ping RPC message");
  1696. X        going_down(3);
  1697. X    }
  1698. X
  1699. X    /*
  1700. X     * Find out how long it is
  1701. X     */
  1702. X    ping_len = xdr_getpos(&ping_xdr);
  1703. X
  1704. X    /*
  1705. X     * Destroy the XDR endpoint - we don't need it anymore
  1706. X     */
  1707. X    xdr_destroy(&ping_xdr);
  1708. X}
  1709. X
  1710. X
  1711. X/*
  1712. X * Called when a portmap reply arrives
  1713. X */
  1714. Xstatic void got_portmap(pkt, len, sa, ia, idv, done)
  1715. Xvoidp pkt;
  1716. Xint len;
  1717. Xstruct sockaddr_in *sa, *ia;
  1718. Xvoidp idv;
  1719. Xint done;
  1720. X{
  1721. X    fserver *fs2 = (fserver *) idv;
  1722. X    fserver *fs = 0;
  1723. X    ITER(fs, fserver, &nfs_srvr_list)
  1724. X        if (fs == fs2)
  1725. X            break;
  1726. X
  1727. X    if (fs == fs2) {
  1728. X        u_long port = 0;    /* XXX - should be short but protocol is naff */
  1729. X        int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, xdr_u_long) : -1;
  1730. X        nfs_private *np = (nfs_private *) fs->fs_private;
  1731. X        if (!error && port) {
  1732. X#ifdef DEBUG
  1733. X            dlog("got port (%d) for mountd on %s", port, fs->fs_host);
  1734. X#endif
  1735. X            /*
  1736. X             * Grab the port number.  Portmap sends back
  1737. X             * an unsigned long in native ordering, so it
  1738. X             * needs converting to a unsigned short in
  1739. X             * network ordering.
  1740. X             */
  1741. X            np->np_mountd = htons((u_short) port);
  1742. X            np->np_error = 0;
  1743. X        } else {
  1744. X#ifdef DEBUG
  1745. X            dlog("Error fetching port for mountd on %s", fs->fs_host);
  1746. X#endif
  1747. X            /*
  1748. X             * Almost certainly no mountd running on remote host
  1749. X             */
  1750. X            np->np_error = error ? error : ETIMEDOUT;
  1751. X        }
  1752. X        if (fs->fs_flags & FSF_WANT)
  1753. X            wakeup_srvr(fs);
  1754. X    } else if (done) {
  1755. X#ifdef DEBUG
  1756. X        dlog("Got portmap for old port request");
  1757. X#endif
  1758. X    } else {
  1759. X#ifdef DEBUG
  1760. X        dlog("portmap request timed out");
  1761. X#endif
  1762. X    }
  1763. X}
  1764. X
  1765. X/*
  1766. X * Obtain portmap information
  1767. X */
  1768. Xstatic int call_portmap(fs, auth, prog, vers, prot)
  1769. Xfserver *fs;
  1770. XAUTH *auth;
  1771. Xunsigned long prog, vers, prot;
  1772. X{
  1773. X    struct rpc_msg pmap_msg;
  1774. X    int len;
  1775. X    char iobuf[UDPMSGSIZE];
  1776. X    int error;
  1777. X    struct pmap pmap;
  1778. X
  1779. X    rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, (unsigned long) 0);
  1780. X    pmap.pm_prog = prog;
  1781. X    pmap.pm_vers = vers;
  1782. X    pmap.pm_prot = prot;
  1783. X    pmap.pm_port = 0;
  1784. X    len = make_rpc_packet(iobuf, sizeof(iobuf), PMAPPROC_GETPORT,
  1785. X            &pmap_msg, (voidp) &pmap, xdr_pmap, auth);
  1786. X    if (len > 0) {
  1787. X        struct sockaddr_in sin;
  1788. X        bzero((voidp) &sin, sizeof(sin));
  1789. X        sin = *fs->fs_ip;
  1790. X        sin.sin_port = htons(PMAPPORT);
  1791. X        error = fwd_packet(RPC_XID_PORTMAP, (voidp) iobuf, len,
  1792. X                &sin, &sin, (voidp) fs, got_portmap);
  1793. X    } else {
  1794. X        error = -len;
  1795. X    }
  1796. X    return error;
  1797. X}
  1798. X
  1799. Xstatic void nfs_keepalive P((fserver*));
  1800. X
  1801. X/*
  1802. X * This is called when we get a reply to an RPC ping.
  1803. X * The value of id wass taken from the nfs_private
  1804. X * structure when the ping was transmitted.
  1805. X */
  1806. X/*ARGSUSED*/
  1807. Xstatic void nfs_pinged(pkt, len, sp, tsp, idv, done)
  1808. Xvoidp pkt;
  1809. Xint len;
  1810. Xstruct sockaddr_in *sp, *tsp;
  1811. Xvoidp idv;
  1812. Xint done;
  1813. X{
  1814. X    int xid = (int) idv;
  1815. X    fserver *fs;
  1816. X    int found_map = 0;
  1817. X
  1818. X    if (!done)
  1819. X        return;
  1820. X
  1821. X    /*
  1822. X     * For each node...
  1823. X     */
  1824. X    ITER(fs, fserver, &nfs_srvr_list) {
  1825. X        nfs_private *np = (nfs_private *) fs->fs_private;
  1826. X        if (np->np_xid == xid) {
  1827. X            /*
  1828. X             * Reset the ping counter.
  1829. X             * Update the keepalive timer.
  1830. X             * Log what happened.
  1831. X             */
  1832. X            if (fs->fs_flags & FSF_DOWN) {
  1833. X                fs->fs_flags &= ~FSF_DOWN;
  1834. X                if (fs->fs_flags & FSF_VALID) {
  1835. X                    plog(XLOG_INFO, "file server %s type nfs is up", fs->fs_host);
  1836. X                } else {
  1837. X                    plog(XLOG_INFO, "file server %s type nfs starts up", fs->fs_host);
  1838. X                    fs->fs_flags |= FSF_VALID;
  1839. X                }
  1840. X                /*if (fs->fs_flags & FSF_WANT)
  1841. X                    wakeup_srvr(fs);*/
  1842. X            } else {
  1843. X#ifdef DEBUG
  1844. X                dlog("file server %s type nfs is still up", fs->fs_host);
  1845. X#endif
  1846. X            }
  1847. X
  1848. X            /*
  1849. X             * Speed up the pings again
  1850. X             */
  1851. X            if (np->np_ping >= MAX_ALLOWED_PINGS) {
  1852. X                untimeout(fs->fs_cid);
  1853. X                fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs);
  1854. X            }
  1855. X
  1856. X            /*
  1857. X             * New RPC xid...
  1858. X             */
  1859. X            np->np_xid = NPXID_ALLOC();
  1860. X
  1861. X            /*
  1862. X             * Failed pings is zero...
  1863. X             */
  1864. X            np->np_ping = 0;
  1865. X
  1866. X            /*
  1867. X             * Recompute portmap information if not known
  1868. X             */
  1869. X            if (np->np_error < 0) {
  1870. X                if (!nfs_auth)
  1871. X                    nfs_auth = authunix_create_default();
  1872. X                if (!nfs_auth)
  1873. X                    np->np_error = ENOBUFS;
  1874. X                else
  1875. X                    call_portmap(fs, nfs_auth, MOUNTPROG,
  1876. X                        MOUNTVERS, (unsigned long) IPPROTO_UDP);
  1877. X            }
  1878. X            found_map++;
  1879. X            break;
  1880. X        }
  1881. X    }
  1882. X
  1883. X#ifdef DEBUG
  1884. X    if (found_map == 0)
  1885. X        dlog("Spurious ping packet");
  1886. X#endif
  1887. X}
  1888. X
  1889. X
  1890. X/*
  1891. X * Keep track of whether a server is alive
  1892. X */
  1893. Xstatic void nfs_keepalive(fs)
  1894. Xfserver *fs;
  1895. X{
  1896. X    int error;
  1897. X    nfs_private *np = (nfs_private *) fs->fs_private;
  1898. X    int fstimeo;
  1899. X
  1900. X    /*
  1901. X     * Send an NFS ping to this node
  1902. X     */
  1903. X
  1904. X    if (ping_len == 0)
  1905. X        start_ping();
  1906. X
  1907. X    /*
  1908. X     * Queue the packet...
  1909. X     */
  1910. X    error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), (voidp) ping_buf,
  1911. X        ping_len, fs->fs_ip, (struct sockaddr_in *) 0, (voidp) np->np_xid, nfs_pinged);
  1912. X
  1913. X    /*
  1914. X     * See if a hard error occured
  1915. X     */
  1916. X    switch (error) {
  1917. X    case ENETDOWN:
  1918. X    case ENETUNREACH:
  1919. X    case EHOSTDOWN:
  1920. X    case EHOSTUNREACH:
  1921. X        np->np_ping = MAX_ALLOWED_PINGS;    /* immediately down */
  1922. X        break;
  1923. X
  1924. X    case 0:
  1925. X#ifdef DEBUG
  1926. X        dlog("Sent NFS ping to %s", fs->fs_host);
  1927. X#endif
  1928. X        break;
  1929. X    }
  1930. X
  1931. X    /*
  1932. X     * If N pings have failed then guess that it is dead
  1933. X     */
  1934. X    if (np->np_ping >= MAX_ALLOWED_PINGS) {
  1935. X        if (!(fs->fs_flags & FSF_VALID)) {
  1936. X            /*
  1937. X             * Starts off down
  1938. X             */
  1939. X            plog(XLOG_INFO, "file server %s type nfs starts down", fs->fs_host);
  1940. X            fs->fs_flags |= FSF_VALID;
  1941. X            if (fs->fs_flags & FSF_WANT)
  1942. X                wakeup_srvr(fs);
  1943. X        }
  1944. X
  1945. X        if ((fs->fs_flags & FSF_DOWN) == 0) {
  1946. X            /*
  1947. X             * Server was up, but is now down.
  1948. X             */
  1949. X            plog(XLOG_INFO, "file server %s type nfs is down", fs->fs_host);
  1950. X            fs->fs_flags |= FSF_DOWN;
  1951. X            if (fs->fs_flags & FSF_WANT)
  1952. X                wakeup_srvr(fs);
  1953. X            /*
  1954. X             * Since the server is down, the portmap
  1955. X             * information may now be wrong, so it
  1956. X             * must be flushed from the local cache
  1957. X             */
  1958. X            flush_fhandle_cache(fs);
  1959. X            np->np_error = -1;
  1960. X            np->np_ping = 1;
  1961. X        }
  1962. X    } else {
  1963. X        np->np_ping++;
  1964. X#ifdef DEBUG
  1965. X        if (np->np_ping > 1)
  1966. X            dlog("%d pings to %s failed - max %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS);
  1967. X#endif
  1968. X    }
  1969. X
  1970. X    /*
  1971. X     * Back off the ping interval if we are not getting replies and
  1972. X     * the remote system is know to be down.
  1973. X     */
  1974. X    switch (fs->fs_flags & (FSF_DOWN|FSF_VALID)) {
  1975. X    case FSF_VALID:            /* Up */
  1976. X        fstimeo = fs->fs_pinger;
  1977. X        break;
  1978. X    case FSF_VALID|FSF_DOWN:    /* Down */
  1979. X        fstimeo = np->np_ping * fs->fs_pinger;
  1980. X        break;
  1981. X    default:            /* Unknown */
  1982. X        fstimeo = FAST_NFS_PING;
  1983. X        break;
  1984. X    }
  1985. X    fs->fs_cid = timeout(fstimeo, nfs_keepalive, (voidp) fs);
  1986. X}
  1987. X
  1988. Xint nfs_srvr_port(fs, port, wchan)
  1989. Xfserver *fs;
  1990. Xu_short *port;
  1991. Xvoidp wchan;
  1992. X{
  1993. X    int error = -1;
  1994. X    if ((fs->fs_flags & FSF_VALID) == FSF_VALID) {
  1995. X        if ((fs->fs_flags & FSF_DOWN) == 0) {
  1996. X            nfs_private *np = (nfs_private *) fs->fs_private;
  1997. X            if (np->np_error == 0) {
  1998. X                *port = np->np_mountd;
  1999. X                /*
  2000. X                 * Now go get it again in case it changed
  2001. X                 */
  2002. X                np->np_error = -1;
  2003. X                error = 0;
  2004. X            } else {
  2005. X                error = np->np_error;
  2006. X            }
  2007. X        } else {
  2008. X            error = EWOULDBLOCK;
  2009. X        }
  2010. X    }
  2011. X    if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) {
  2012. X        /*
  2013. X         * If a wait channel is supplied, and no
  2014. X         * error has yet occured, then arrange
  2015. X         * that a wakeup is done on the wait channel,
  2016. X         * whenever a wakeup is done on this fs node.
  2017. X         * Wakeup's are done on the fs node whenever
  2018. X         * it changes state - thus causing control to
  2019. X         * come back here and new, better things to happen.
  2020. X         */
  2021. X        fs->fs_flags |= FSF_WANT;
  2022. X        sched_task(wakeup_task, wchan, (voidp) fs);
  2023. X    }
  2024. X    return error;
  2025. X}
  2026. X
  2027. Xstatic void start_nfs_pings(fs)
  2028. Xfserver *fs;
  2029. X{
  2030. X    if (!(fs->fs_flags & FSF_PINGING)) {
  2031. X        fs->fs_flags |= FSF_PINGING;
  2032. X        if (fs->fs_cid)
  2033. X            untimeout(fs->fs_cid);
  2034. X        nfs_keepalive(fs);
  2035. X    } else {
  2036. X#ifdef DEBUG
  2037. X        dlog("Already running pings to %s", fs->fs_host);
  2038. X#endif
  2039. X    }
  2040. X}
  2041. X
  2042. X/*
  2043. X * Find an nfs server for a host.
  2044. X */
  2045. Xfserver *find_nfs_srvr(mf)
  2046. Xmntfs *mf;
  2047. X{
  2048. X    fserver *fs;
  2049. X    struct hostent *hp = 0;
  2050. X    char *host = mf->mf_fo->opt_rhost;
  2051. X    struct sockaddr_in *ip;
  2052. X    nfs_private *np;
  2053. X
  2054. Xtop:
  2055. X    /*
  2056. X     * Scan the list of known servers looking
  2057. X     * for one with the same name
  2058. X     */
  2059. X    ITER(fs, fserver, &nfs_srvr_list) {
  2060. X        if (STREQ(host, fs->fs_host)) {
  2061. X            start_nfs_pings(fs);
  2062. X            fs->fs_refc++;
  2063. X            return fs;
  2064. X        }
  2065. X    }
  2066. X
  2067. X    /*
  2068. X     * If the name is not known, it may be
  2069. X     * because it was an alternate name for
  2070. X     * the same machine.  So do a lookup and
  2071. X     * try again with the primary name if that
  2072. X     * is different.
  2073. X     * All that assuming it wasn't normalized
  2074. X     * earlier of course...
  2075. X     */
  2076. X    if (hp == 0) {
  2077. X        hp = gethostbyname(host);
  2078. X        if (hp && !STREQ(host, hp->h_name) && !normalize_hosts) {
  2079. X            host = hp->h_name;
  2080. X            goto top;
  2081. X        }
  2082. X    }
  2083. X
  2084. X    /*
  2085. X     * Get here if we can't find an entry
  2086. X     */
  2087. X    if (hp) {
  2088. X        switch (hp->h_addrtype) {
  2089. X        case AF_INET:
  2090. X            ip = ALLOC(sockaddr_in);
  2091. X            bzero((voidp) ip, sizeof(*ip));
  2092. X            ip->sin_family = AF_INET;
  2093. X            ip->sin_addr = *(struct in_addr *) hp->h_addr;
  2094. X            ip->sin_port = htons(NFS_PORT);
  2095. X            break;
  2096. X
  2097. X        default:
  2098. X            ip = 0;
  2099. X            break;
  2100. X        }
  2101. X    } else {
  2102. X        ip = 0;
  2103. X    }
  2104. X
  2105. X    /*
  2106. X     * Allocate a new server
  2107. X     */
  2108. X    fs = ALLOC(fserver);
  2109. X    fs->fs_refc = 1;
  2110. X    fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname");
  2111. X    fs->fs_ip = ip;
  2112. X    fs->fs_cid = 0;
  2113. X    if (ip) {
  2114. X        fs->fs_flags = FSF_DOWN;    /* Starts off down */
  2115. X    } else {
  2116. X        fs->fs_flags = FSF_ERROR|FSF_VALID;
  2117. X        mf->mf_flags |= MFF_ERROR;
  2118. X        mf->mf_error = ENOENT;
  2119. X    }
  2120. X    fs->fs_pinger = AM_PINGER;
  2121. X    np = ALLOC(nfs_private);
  2122. X    np->np_xid = NPXID_ALLOC();
  2123. X    bzero((voidp) np, sizeof(*np));
  2124. X    np->np_error = -1;
  2125. X    fs->fs_private = (voidp) np;
  2126. X    fs->fs_prfree = free;
  2127. X
  2128. X    if (!(fs->fs_flags & FSF_ERROR)) {
  2129. X        /*
  2130. X         * Start of keepalive timer
  2131. X         */
  2132. X        start_nfs_pings(fs);
  2133. X    }
  2134. X
  2135. X    /*
  2136. X     * Add to list of servers
  2137. X     */
  2138. X    ins_que(&fs->fs_q, &nfs_srvr_list);
  2139. X
  2140. X    return fs;
  2141. X}
  2142. END_OF_FILE
  2143. if test 11929 -ne `wc -c <'srvr_nfs.c'`; then
  2144.     echo shar: \"'srvr_nfs.c'\" unpacked with wrong size!
  2145. fi
  2146. # end of 'srvr_nfs.c'
  2147. fi
  2148. echo shar: End of archive 8 \(of 13\).
  2149. cp /dev/null ark8isdone
  2150. MISSING=""
  2151. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  2152.     if test ! -f ark${I}isdone ; then
  2153.     MISSING="${MISSING} ${I}"
  2154.     fi
  2155. done
  2156. if test "${MISSING}" = "" ; then
  2157.     echo You have unpacked all 13 archives.
  2158.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2159. else
  2160.     echo You still need to unpack the following archives:
  2161.     echo "        " ${MISSING}
  2162. fi
  2163. ##  End of shell archive.
  2164. exit 0
  2165. exit 0 # Just in case...
  2166.